<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Promise原理</title>
	</head>
	<body>
        <h1>Promise原理</h1>
	</body>
    <script type="text/javascript">
        function P(executor){
            let self = this;
            self.status = 'pending';
            self.value = null;
            self.reson = null;
            self.onfulfilledCallbacks =[];
            self.onrejectedCallbacks =[];

            function resolve(vl){
                if(self.status == 'pending'){
                    self.value = vl;
                    self.status = 'fulfilled';
                    self.onfulfilledCallbacks.forEach(f => {
                        f()
                    });
                    
                }
            }

            function reject(err){
                if(self.status == 'pending'){
                    self.reson = err;
                    self.status = 'rejected';
                    self.onrejectedCallbacks.forEach(f => {
                        f()
                    });
                    
                }
            }
            
            try{
                executor(resolve,reject);
            }catch(err){
                reject(err)
            }
            
        }

        P.prototype.then = function(f1,f2){

            let that = this;

            let p2 = new P((resolve,reject)=>{
                console.log(this)
                if(this.status=='fulfilled'){
                    setTimeout(()=>{
                        try{
                            let x = f1(this.value)
                            resolvePromise(p2, x, resolve, reject)
                        }catch(e){
                            reject(e)
                        }
                    },0)
                }
                if(this.status=='rejected'){
                    setTimeout(()=>{
                        try{
                            let x = f2(this.reson)
                            resolvePromise(p2, x, resolve, reject)
                        }catch(e){
                            reject(e)
                        }
                    },0)
                }
                if(this.status == 'pending'){
                    this.onfulfilledCallbacks.push(()=>{
                        setTimeout(() => {
                            try {
                                // 有一个返回值x，运行解析函数resolvePromise
                                let x = f1(this.value);
                                resolvePromise(p2, x, resolve, reject)
                            } catch (e) {
                                reject(e);
                            }
                        }, 0);
                    })
                    this.onrejectedCallbacks.push(()=>{
                        setTimeout(() => {
                            try {
                                // 有一个返回值x，运行解析函数resolvePromise
                                let x = f2(this.reason);;
                                resolvePromise(p2, x, resolve, reject)
                            } catch (e) {
                                reject(e);
                            }
                        }, 0);
                    })
                }
            })

            // if(this.status == 'pending'){
            //     this.onfulfilledCallbacks.push(()=>f1(this.value));
            //     this.onrejectedCallbacks.push(()=>f2(this.reson));
            // }
            
            return p2;
        }

        function resolvePromise(promise2,x,resolve,reject){
            // promise2和函数执行后返回的结果是同一个对象
            
            if(promise2 === x){
                return reject(new TypeError('Chaining cycle'));
            }
            // x可能是一个promise 或者是一个普通值
            if(x!==null && (typeof x=== 'object' || typeof x === 'function')){
                try{
                    let then = x.then; 
                    // 取对象上的属性 怎么能报异常呢？(这个promise不一定是自己写的 可能是别人写的 有的人会乱写)
                    // x可能还是一个promise 那么就让这个promise执行即可
                    // {then:{}}
                    // 这里的逻辑不单单是自己的 还有别人的 别人的promise 可能既会调用成功 也会调用失败
                    if(typeof then === 'function'){
                        then.call(x,y=>{ // 返回promise后的成功结果
                            // 递归直到解析成普通值为止
                            // 递归 可能成功后的结果是一个promise 那就要循环的去解析
                            resolvePromise(promise2,y,resolve,reject);
                        },err=>{ // promise的失败结果
                            reject(err);
                        });
                    }else{
                        resolve(x);
                    }
                }catch(e){
                    reject(e);
                }
            }else{ // 如果x是一个常量
                resolve(x);
            }
        }

        // P.prototype.catch = function(f){
        //     this.onrejectedCallbacks.push(f);
        //     return this;
        // }
        
        const p = new P((resolve,reject)=>{
            setTimeout(()=>{
                resolve(1000)
            },500)
        }).then((data)=>{
            console.log('data',data)
            return new P((resolve,reject)=>{
                resolve(data)
            })
        }).then((result)=>{
            console.log('result',result)
        })

	</script>
</html>
